home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Log / mdb2.php < prev    next >
Encoding:
PHP Script  |  2006-04-07  |  10.6 KB  |  359 lines

  1. <?php
  2. /**
  3.  * $Header: /repository/pear/Log/Log/mdb2.php,v 1.3 2005/10/24 05:02:33 jon Exp $
  4.  *
  5.  * @version $Revision: 1.3 $
  6.  * @package Log
  7.  */
  8.  
  9. /** PEAR's MDB2 package */
  10. require_once 'MDB2.php';
  11. MDB2::loadFile('Date');
  12.  
  13. /**
  14.  * The Log_mdb2 class is a concrete implementation of the Log:: abstract class
  15.  * which sends messages to an SQL server.  Each entry occupies a separate row
  16.  * in the database.
  17.  *
  18.  * This implementation uses PEAR's MDB2 database abstraction layer.
  19.  *
  20.  * CREATE TABLE log_table (
  21.  *  id          INT NOT NULL,
  22.  *  logtime     TIMESTAMP NOT NULL,
  23.  *  ident       CHAR(16) NOT NULL,
  24.  *  priority    INT NOT NULL,
  25.  *  message     VARCHAR(200),
  26.  *  PRIMARY KEY (id)
  27.  * );
  28.  *
  29.  * @author  Lukas Smith <smith@backendmedia.com>
  30.  * @author  Jon Parise <jon@php.net>
  31.  * @since   Log 1.9.0
  32.  * @package Log
  33.  */
  34. class Log_mdb2 extends Log
  35. {
  36.     /**
  37.      * Variable containing the DSN information.
  38.      * @var mixed
  39.      * @access private
  40.      */
  41.     var $_dsn = '';
  42.  
  43.     /**
  44.      * Array containing our set of DB configuration options.
  45.      * @var array
  46.      * @access private
  47.      */
  48.     var $_options = array('persistent' => true);
  49.  
  50.     /**
  51.      * Object holding the database handle.
  52.      * @var object
  53.      * @access private
  54.      */
  55.     var $_db = null;
  56.  
  57.     /**
  58.      * Resource holding the prepared statement handle.
  59.      * @var resource
  60.      * @access private
  61.      */
  62.     var $_statement = null;
  63.  
  64.     /**
  65.      * Flag indicating that we're using an existing database connection.
  66.      * @var boolean
  67.      * @access private
  68.      */
  69.     var $_existingConnection = false;
  70.  
  71.     /**
  72.      * String holding the database table to use.
  73.      * @var string
  74.      * @access private
  75.      */
  76.     var $_table = 'log_table';
  77.  
  78.     /**
  79.      * String holding the name of the ID sequence.
  80.      * @var string
  81.      * @access private
  82.      */
  83.     var $_sequence = 'log_id';
  84.  
  85.     /**
  86.      * Maximum length of the $ident string.  This corresponds to the size of
  87.      * the 'ident' column in the SQL table.
  88.      * @var integer
  89.      * @access private
  90.      */
  91.     var $_identLimit = 16;
  92.  
  93.     /**
  94.      * Set of field types used in the database table.
  95.      * @var array
  96.      * @access private
  97.      */
  98.     var $_types = array(
  99.         'id'        => 'integer',
  100.         'logtime'   => 'timestamp',
  101.         'ident'     => 'text',
  102.         'priority'  => 'text',
  103.         'message'   => 'clob'
  104.     );
  105.  
  106.     /**
  107.      * Constructs a new sql logging object.
  108.      *
  109.      * @param string $name         The target SQL table.
  110.      * @param string $ident        The identification field.
  111.      * @param array $conf          The connection configuration array.
  112.      * @param int $level           Log messages up to and including this level.
  113.      * @access public
  114.      */
  115.     function Log_mdb2($name, $ident = '', $conf = array(),
  116.                      $level = PEAR_LOG_DEBUG)
  117.     {
  118.         $this->_id = md5(microtime());
  119.         $this->_table = $name;
  120.         $this->_mask = Log::UPTO($level);
  121.  
  122.         /* If an options array was provided, use it. */
  123.         if (isset($conf['options']) && is_array($conf['options'])) {
  124.             $this->_options = $conf['options'];
  125.         }
  126.  
  127.         /* If a specific sequence name was provided, use it. */
  128.         if (!empty($conf['sequence'])) {
  129.             $this->_sequence = $conf['sequence'];
  130.         }
  131.  
  132.         /* If a specific sequence name was provided, use it. */
  133.         if (isset($conf['identLimit'])) {
  134.             $this->_identLimit = $conf['identLimit'];
  135.         }
  136.  
  137.         /* Now that the ident limit is confirmed, set the ident string. */
  138.         $this->setIdent($ident);
  139.  
  140.         /* If an existing database connection was provided, use it. */
  141.         if (isset($conf['db'])) {
  142.             $this->_db = &$conf['db'];
  143.             $this->_existingConnection = true;
  144.             $this->_opened = true;
  145.         } elseif (isset($conf['singleton'])) {
  146.             $this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
  147.             $this->_existingConnection = true;
  148.             $this->_opened = true;
  149.         } else {
  150.             $this->_dsn = $conf['dsn'];
  151.         }
  152.     }
  153.  
  154.     /**
  155.      * Opens a connection to the database, if it has not already
  156.      * been opened. This is implicitly called by log(), if necessary.
  157.      *
  158.      * @return boolean   True on success, false on failure.
  159.      * @access public
  160.      */
  161.     function open()
  162.     {
  163.         if (!$this->_opened) {
  164.             /* Use the DSN and options to create a database connection. */
  165.             $this->_db = &MDB2::connect($this->_dsn, $this->_options);
  166.             if (PEAR::isError($this->_db)) {
  167.                 return false;
  168.             }
  169.  
  170.             /* Create a prepared statement for repeated use in log(). */
  171.             if (!$this->_prepareStatement()) {
  172.                 return false;
  173.             }
  174.  
  175.             /* We now consider out connection open. */
  176.             $this->_opened = true;
  177.         }
  178.  
  179.         return $this->_opened;
  180.     }
  181.  
  182.     /**
  183.      * Closes the connection to the database if it is still open and we were
  184.      * the ones that opened it.  It is the caller's responsible to close an
  185.      * existing connection that was passed to us via $conf['db'].
  186.      *
  187.      * @return boolean   True on success, false on failure.
  188.      * @access public
  189.      */
  190.     function close()
  191.     {
  192.         /* If we have a statement object, free it. */
  193.         if (is_object($this->_statement)) {
  194.             $this->_statement->free();
  195.             $this->_statement = null;
  196.         }
  197.  
  198.         /* If we opened the database connection, disconnect it. */
  199.         if ($this->_opened && !$this->_existingConnection) {
  200.             $this->_opened = false;
  201.             return $this->_db->disconnect();
  202.         }
  203.  
  204.         return ($this->_opened === false);
  205.     }
  206.  
  207.     /**
  208.      * Sets this Log instance's identification string.  Note that this
  209.      * SQL-specific implementation will limit the length of the $ident string
  210.      * to sixteen (16) characters.
  211.      *
  212.      * @param string    $ident      The new identification string.
  213.      *
  214.      * @access  public
  215.      * @since   Log 1.8.5
  216.      */
  217.     function setIdent($ident)
  218.     {
  219.         $this->_ident = substr($ident, 0, $this->_identLimit);
  220.     }
  221.  
  222.     /**
  223.      * Inserts $message to the currently open database.  Calls open(),
  224.      * if necessary.  Also passes the message along to any Log_observer
  225.      * instances that are observing this Log.
  226.      *
  227.      * @param mixed  $message  String or object containing the message to log.
  228.      * @param string $priority The priority of the message.  Valid
  229.      *                  values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
  230.      *                  PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
  231.      *                  PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
  232.      * @return boolean  True on success or false on failure.
  233.      * @access public
  234.      */
  235.     function log($message, $priority = null)
  236.     {
  237.         /* If a priority hasn't been specified, use the default value. */
  238.         if ($priority === null) {
  239.             $priority = $this->_priority;
  240.         }
  241.  
  242.         /* Abort early if the priority is above the maximum logging level. */
  243.         if (!$this->_isMasked($priority)) {
  244.             return false;
  245.         }
  246.  
  247.         /* If the connection isn't open and can't be opened, return failure. */
  248.         if (!$this->_opened && !$this->open()) {
  249.             return false;
  250.         }
  251.  
  252.         /* If we don't already have a statement object, create one. */
  253.         if (!is_object($this->_statement) && !$this->_prepareStatement()) {
  254.             return false;
  255.         }
  256.  
  257.         /* Extract the string representation of the message. */
  258.         $message = $this->_extractMessage($message);
  259.  
  260.         /* Build our set of values for this log entry. */
  261.         $values = array(
  262.             'id'       => $this->_db->nextId($this->_sequence),
  263.             'logtime'  => MDB2_Date::mdbNow(),
  264.             'ident'    => $this->_ident,
  265.             'priority' => $priority,
  266.             'message'  => $message
  267.         );
  268.  
  269.         /* Execute the SQL query for this log entry insertion. */
  270.         $this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
  271.         $result = &$this->_statement->execute($values);
  272.         $this->_db->popExpect();
  273.  
  274.         /* Attempt to handle any errors. */
  275.         if (PEAR::isError($result)) {
  276.             /* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
  277.             if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
  278.                 return false;
  279.             }
  280.  
  281.             /* Attempt to create the target table. */
  282.             if (!$this->_createTable()) {
  283.                 return false;
  284.             }
  285.  
  286.             /* Recreate our prepared statement resource. */
  287.             $this->_statement->free();
  288.             if (!$this->_prepareStatement()) {
  289.                 return false;
  290.             }
  291.  
  292.             /* Attempt to re-execute the insertion query. */
  293.             $result = $this->_statement->execute($values);
  294.             if (PEAR::isError($result)) {
  295.                 return false;
  296.             }
  297.         }
  298.  
  299.         $this->_announce(array('priority' => $priority, 'message' => $message));
  300.  
  301.         return true;
  302.     }
  303.  
  304.     /**
  305.      * Create the log table in the database.
  306.      *
  307.      * @return boolean  True on success or false on failure.
  308.      * @access private
  309.      */
  310.     function _createTable()
  311.     {
  312.         $this->_db->loadModule('Manager');
  313.         $result = $this->_db->manager->createTable(
  314.             $this->_table,
  315.             array(
  316.                 'id'        => array('type' => $this->_types['id']),
  317.                 'logtime'   => array('type' => $this->_types['logtime']),
  318.                 'ident'     => array('type' => $this->_types['ident']),
  319.                 'priority'  => array('type' => $this->_types['priority']),
  320.                 'message'   => array('type' => $this->_types['message'])
  321.             )
  322.         );
  323.         if (PEAR::isError($result)) {
  324.             return false;
  325.         }
  326.  
  327.         $result = $this->_db->manager->createIndex(
  328.             $this->_table,
  329.             'unique_id',
  330.             array('fields' => array('id' => true), 'unique' => true)
  331.         );
  332.         if (PEAR::isError($result)) {
  333.             return false;
  334.         }
  335.  
  336.         return true;
  337.     }
  338.  
  339.     /**
  340.      * Prepare the SQL insertion statement.
  341.      *
  342.      * @return boolean  True if the statement was successfully created.
  343.      *
  344.      * @access  private
  345.      * @since   Log 1.9.0
  346.      */
  347.     function _prepareStatement()
  348.     {
  349.         $this->_statement = &$this->_db->prepare(
  350.                 'INSERT INTO ' . $this->_table .
  351.                 ' (id, logtime, ident, priority, message)' .
  352.                 ' VALUES(:id, :logtime, :ident, :priority, :message)',
  353.                 $this->_types);
  354.  
  355.         /* Return success if we didn't generate an error. */
  356.         return (PEAR::isError($this->_statement) === false);
  357.     }
  358. }
  359.